#include <ctime>
#include <unistd.h>
#include <cstdlib>
#include <pthread.h>
#include <curses.h>

int word;
#define up    1
#define down  -1
#define left  2
#define right -2
typedef struct snake {
    int hang;
    int lie;
    struct snake *next;
} Snake;
Snake *head = NULL;
Snake *tail = NULL;
Snake food;

void initFood() {
    srand((unsigned) time(NULL));
    static int x = 4;
    static int y = 5;
    food.hang = x;
    food.lie = y;
    x = rand() % (40 - x);
    y = rand() % (40 - y);
}

int foodSeat(int i, int j) {
    if (food.hang == i && food.lie == j) {
        return 1;
    }
    return 0;
}

int SnakeNode(int i, int j) {
    Snake *p = head;
    while (p != NULL) {
        if (p->hang == i && p->lie == j) {
            return 1;
        }
        p = p->next;
    }
    return 0;
}

void initNcurses() {
    initscr();
    keypad(stdscr, 1);
    noecho();
}

void initGamePic() {
    int hang;
    int lie;
    move(0, 0);
    for (hang = 0; hang < 40; hang++) {
        if (hang == 0) {
            for (lie = 0; lie < 40; lie++) {
                printw("--");
            }
        }
        printw("\n");
        for (lie = 0; lie < 40; lie++) {
            if (lie == 0 || lie == 39) {
                printw("|");
            }
            if (SnakeNode(hang, lie)) {
                printw("[]");
            } else if (foodSeat(hang, lie)) {
                printw("##");
            } else {
                printw("  ");
            }
        }
        if (hang == 39) {
            printw("\n");
            for (lie = 0; lie < 40; lie++) {
                printw("--");
            }
        }
    }
    printw("\nBY TangXin");
}

void addNode() {
    Snake *newNode = (Snake *) malloc(sizeof(Snake));
    if (word == right) {
        newNode->hang = tail->hang;
        newNode->lie = tail->lie + 1;
    }
    if (word == left) {
        newNode->hang = tail->hang;
        newNode->lie = tail->lie - 1;
    }
    if (word == up) {
        newNode->hang = tail->hang - 1;
        newNode->lie = tail->lie;
    }
    if (word == down) {
        newNode->hang = tail->hang + 1;
        newNode->lie = tail->lie;
    }
    newNode->next = NULL;
    tail->next = newNode;
    tail = newNode;
}

void initSnakeNode() {
    word = right;
    initFood();
    head = (Snake *) malloc(sizeof(Snake));
    head->hang = 2;
    head->lie = 0;
    head->next = NULL;
    tail = head;
    addNode();
    addNode();
    addNode();
}

void deleteNode() {
    Snake *p;
    p = head;
    head = head->next;
    free(p);
}

int SnakeDie() {
    Snake *p = head;
    if (tail->hang == -1 || tail->hang == 40 || tail->lie == -1 || tail->lie == 40) {
        return 1;
    }
    while (p->next != NULL) {
        if (p->hang == tail->hang && p->lie == tail->lie) {
            return 1;
        }
        p = p->next;
    }
    return 0;
}

void moveSnake() {
    addNode();
    if (foodSeat(tail->hang, tail->lie)) {
        initFood();
    } else {
        deleteNode();
    }
    if (SnakeDie()) {
        initSnakeNode();
    }

}

void *refreshPic() {
    while (1) {
        moveSnake();
        initGamePic();
        refresh();
        usleep(100000);
    }
}

void turn(int word1) {
    if (abs(word) != abs(word1)) {
        word = word1;
    }
}

void *changeWord() {
    int key;
    while (1) {
        key = getch();
        switch (key) {
            case KEY_RIGHT:
                turn(right);
                break;
            case KEY_LEFT:
                turn(left);
                break;
            case KEY_UP:
                turn(up);
                break;
            case KEY_DOWN:
                turn(down);
                break;
        }
    }
}

int main() {
    pthread_t t1;
    pthread_t t2;
    initNcurses();
    initSnakeNode();
    initGamePic();
    pthread_create(&t1, NULL, reinterpret_cast<void *(*)(void *)>(refreshPic), NULL);
    pthread_create(&t2, NULL, reinterpret_cast<void *(*)(void *)>(changeWord), NULL);
    while (1);
    getch();
    endwin();
    return 0;
}

